﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="DropHandler.cs" company="">
//   
// </copyright>
// <summary>
//   The drop handler.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Libium.Controls
{
    using System;
    using System.Collections.Generic;
    using System.Windows.Forms;

    using Libium.Core;
    using Libium.WindowsForms.Controls;

    /// <summary>
    /// The drop handler.
    /// </summary>
    public class DropHandler : Disposable
    {
        #region Fields

        /// <summary>
        /// The _controls.
        /// </summary>
        private readonly List<Control> _controls = new List<Control>();

        #endregion

        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="DropHandler"/> class.
        /// </summary>
        /// <param name="target">
        /// The target.
        /// </param>
        public DropHandler(IPasteTarget target = null)
        {
            Target = target;
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets or sets the target.
        /// </summary>
        public IPasteTarget Target { get; set; }

        #endregion

        #region Public Methods and Operators

        /// <summary>
        /// The copy action to drag drop effects.
        /// </summary>
        /// <param name="action">
        /// The action.
        /// </param>
        /// <returns>
        /// The <see cref="DragDropEffects"/>.
        /// </returns>
        public static DragDropEffects CopyActionToDragDropEffects(CopyAction action)
        {
            var effects = DragDropEffects.None;

            if (action == CopyAction.Copy)
            {
                effects |= DragDropEffects.Copy;
            }
            else if (action == CopyAction.Move)
            {
                effects |= DragDropEffects.Move;
            }
            else if (action == CopyAction.Link)
            {
                effects |= DragDropEffects.Link;
            }

            return effects;
        }

        /// <summary>
        /// The drag drop effect to copy action.
        /// </summary>
        /// <param name="effect">
        /// The effect.
        /// </param>
        /// <returns>
        /// The <see cref="CopyAction"/>.
        /// </returns>
        public static CopyAction DragDropEffectToCopyAction(DragDropEffects effect)
        {
            var action = CopyAction.None;

            if ((effect & DragDropEffects.Copy) != 0)
            {
                action = CopyAction.Copy;
            }
            else if ((effect & DragDropEffects.Move) != 0)
            {
                action = CopyAction.Move;
            }

            if ((effect & DragDropEffects.Link) != 0)
            {
                action = CopyAction.Link;
            }

            return action;
        }

        /// <summary>
        /// The add control.
        /// </summary>
        /// <param name="control">
        /// The control.
        /// </param>
        public void AddControl(Control control)
        {
            control.AllowDrop = true;
            control.DragEnter += OnDragEnter;
				control.DragLeave += OnDragLeave;
            control.DragOver += OnDragOver;
            control.DragDrop += OnDragDrop;
            _controls.Add(control);
        }

        #endregion

        #region Methods

        /// <summary>
        /// The do dispose.
        /// </summary>
        protected override void DoDispose()
        {
            foreach (var control in _controls)
            {
                control.DragEnter -= OnDragEnter;
                control.DragLeave -= OnDragLeave;
                control.DragOver -= OnDragOver;
                control.DragDrop -= OnDragDrop;
            }
        }

        /// <summary>
        /// The on drag drop.
        /// </summary>
        /// <param name="source">
        /// The source.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
		  protected virtual void OnDragDrop(object source, DragEventArgs e)
		  {
			  if (Target == null)
			  {
				  return;
			  }

			  var action = DragDropEffectToCopyAction(e.Effect);

			  if (action != CopyAction.None)
			  {
				  Target.Paste(new PasteDataObject(e.Data), action);
			  }




			  try
			  {
				  CollapseableStackItemsControl stackControl = GetScrollableControl((Control)source);
				  if (stackControl != null)
					  stackControl.OnMouseUp(source, e);
			  }
			  catch (Exception ex)
			  {
				  Console.WriteLine();
			  }
		  }

        /// <summary>
        /// The on drag enter.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="dragEventArgs">
        /// The drag event args.
        /// </param>
        protected virtual void OnDragEnter(object sender, DragEventArgs dragEventArgs)
        {
			  BindableUserControl bindableParent = ((Control)sender).Parent as BindableUserControl;
			  if (bindableParent != null)
			  {
				  try
				  {
					  CollapseableStackItemsControl stackControl = GetScrollableControl((Control)sender);
					  if (stackControl != null)
						  stackControl.OnDragEnter(sender, dragEventArgs);
				  }
				  catch (Exception ex)
				  {
					  Console.WriteLine();
				  }
			  }
        }

        /// <summary>
        /// The on drag leave.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="eventArgs">
        /// The event args.
        /// </param>
		  protected virtual void OnDragLeave(object sender, EventArgs eventArgs)
		  {
			  /************ Start ScrollBar Games *************/
			  try
			  {
				  CollapseableStackItemsControl stackControl = GetScrollableControl((Control)sender);
				  if (stackControl != null)
					  stackControl.OnDragLeave(sender, eventArgs);
			  }
			  catch (Exception ex)
			  {
				  Console.WriteLine();
			  }
			  /************ End Scroll Bar Games **************/
        }

        /// <summary>
        /// The on drag over.
        /// </summary>
        /// <param name="source">
        /// The source.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
		  protected virtual void OnDragOver(object source, DragEventArgs e)
		  {
			  /************ Start ScrollBar Games *************/
			  try
			  {
				  CollapseableStackItemsControl stackControl = GetScrollableControl((Control)source);
				  if (stackControl != null)
					  stackControl.OnDragOver(source, e);
			  }
			  catch (Exception ex)
			  {
				  Console.WriteLine();
			  }
			  /************ End Scroll Bar Games **************/

			  var effect = DragDropEffects.None;

			  if (Target == null)
			  {
				  return;
			  }

			  var pasteData = new PasteDataObject(e.Data);

			  if (pasteData.IsExist("Libium.Source"))
			  {
				  var control = (Control)e.Data.GetData("Libium.Source");
				  if (control == source)
				  {
					  return;
				  }
			  }

			  var options = Target.GetPasteOptions(pasteData);
			  var allowedEffect = e.AllowedEffect;

			  if (!options.CanCopy)
			  {
				  allowedEffect &= ~DragDropEffects.Copy;
			  }

			  if (!options.CanMove)
			  {
				  allowedEffect &= ~DragDropEffects.Move;
			  }

			  if (!options.CanLink)
			  {
				  allowedEffect &= ~DragDropEffects.Link;
			  }

			  if (allowedEffect == 0)
			  {
				  return;
			  }

			  // Reflect to keyboard shortcuts
			  if ((e.KeyState & (8 + 32)) == (8 + 32))
			  {
				  // Alt
				  effect = DragDropEffects.Link;
			  }
			  else if ((e.KeyState & 32) == 32)
			  {
				  // Alt
				  effect = DragDropEffects.Link;
			  }
			  else if ((e.KeyState & 8) == 8)
			  {
				  // Ctrl
				  effect = DragDropEffects.Copy;
			  }
			  else if ((e.KeyState & 4) == 4)
			  {
				  // Shift
				  effect = DragDropEffects.Move;
			  }
			  else
			  {
				  effect = CopyActionToDragDropEffects(options.DefaultAction);
			  }

			  if ((allowedEffect & effect) != effect)
			  {
				  effect = CopyActionToDragDropEffects(options.DefaultAction);
			  }

			  if ((allowedEffect & effect) != effect)
			  {
				  effect = DragDropEffects.Copy;
			  }

			  if ((allowedEffect & effect) != effect)
			  {
				  effect = DragDropEffects.Move;
			  }

			  if ((allowedEffect & effect) != effect)
			  {
				  effect = DragDropEffects.Link;
			  }

			  if ((allowedEffect & effect) != effect)
			  {
				  effect = DragDropEffects.None;
			  }

			  e.Effect = effect;
		  }

		  private CollapseableStackItemsControl GetScrollableControl(Control source)
		  {
			  Control parent = source.Parent;
			  CollapseableStackItemsControl stackControl = null;
			  while (stackControl == null)
			  {
				  if (parent is CollapseableStackItemsControl)
					  stackControl = parent as CollapseableStackItemsControl;
				  parent = parent.Parent;
			  }
			  return stackControl;
		  }

        #endregion
    }
}